package com.example.controller.user;

import com.example.config.ProjectProperties;
import com.example.dto.request.user.UserAccountHelpRequestDTO;
import com.example.exception.db.UpdateException;
import com.example.exception.user.VerificationCodeMismatchException;
import com.example.pojo.User;
import com.example.response.ErrorStatus;
import com.example.response.ApiResult;
import com.example.vo.user.UserAccountHelpRequestVO;
import com.example.service.user.UserAccountHelpService;
import com.example.service.cache.StringCacheService;
import com.example.service.user.UserQueryService;
import com.example.dto.request.user.VerificationCodeMailRequestDTO;
import com.example.service.user.impl.UserAuthorizationServiceImpl;
import com.example.util.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mail.MailException;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.mail.MessagingException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author LeXin Huang
 * @date 2021年03月22日 10:52
 */
@Api(tags = "用户账号帮助模块")
@Slf4j
@RestController
public class AccountHelpController {

    private final String MAIL_TITLE;

    private final String VERIFICATION_CODE_CACHE_PREFIX;

    private final int VERIFICATION_CODE_LEN;

    private final long VERIFICATION_CODE_TIME_OUT;

    private final TimeUnit VERIFICATION_CODE_TIME_UNIT;

    private final String VERIFICATION_CODE_TIME_UNIT_NAME;

    private final String DEFAULT_VERIFICATION_CODE;

    private final UserAccountHelpService userAccountHelpService;

    private final UserAuthorizationServiceImpl userAuthorizationService;

    private final UserQueryService userQueryService;

    private final StringCacheService stringCacheService;

    public AccountHelpController(ProjectProperties projectProperties,
                                 UserAccountHelpService userAccountHelpService,
                                 UserAuthorizationServiceImpl userAuthorizationService,
                                 UserQueryService userQueryService,
                                 StringCacheService stringCacheService) {
        this.VERIFICATION_CODE_CACHE_PREFIX = projectProperties.getVerificationCode().getCachePrefix();
        this.VERIFICATION_CODE_LEN = projectProperties.getVerificationCode().getLen();
        this.VERIFICATION_CODE_TIME_OUT = projectProperties.getVerificationCode().getTimeOut();
        this.VERIFICATION_CODE_TIME_UNIT_NAME = projectProperties.getVerificationCode().getDisplayUnitName();
        this.VERIFICATION_CODE_TIME_UNIT = projectProperties.getVerificationCode().getTimeUnit();
        this.DEFAULT_VERIFICATION_CODE = projectProperties.getVerificationCode().getDefaultCode();
        this.MAIL_TITLE = projectProperties.getMail().getAccountVerificationSubject();
        this.userAccountHelpService = userAccountHelpService;
        this.userAuthorizationService = userAuthorizationService;
        this.userQueryService = userQueryService;
        this.stringCacheService = stringCacheService;
    }

    @PostMapping("/email_check")
    @ApiOperation("找回密码-发送邮件接口")
    public ApiResult<UserAccountHelpRequestVO> emailCheck(@Validated(value =
            {UserAccountHelpRequestDTO.EmailCheckGroup.class}) @RequestBody UserAccountHelpRequestDTO request) {
        User user = userQueryService.getByUsername(request.getUsername());
        ApiResult<UserAccountHelpRequestVO> response = new ApiResult<>();
        String vfCode = this.DEFAULT_VERIFICATION_CODE;
        if (!Objects.isNull(user)) {
                vfCode = StringUtil.getCodeString(this.VERIFICATION_CODE_LEN);
                VerificationCodeMailRequestDTO mailInfo = new VerificationCodeMailRequestDTO();
                mailInfo.setRecipientAddress(user.getEmailAddress());
                mailInfo.setRecipientName(user.getUsername());
                mailInfo.setSubject(this.MAIL_TITLE);
                mailInfo.setCode(vfCode);
                mailInfo.setTimeOut(this.VERIFICATION_CODE_TIME_OUT);
                mailInfo.setTimeUnitName(this.VERIFICATION_CODE_TIME_UNIT_NAME);
                String k = this.VERIFICATION_CODE_CACHE_PREFIX + user.getUsername();
                stringCacheService.set(k, vfCode, this.VERIFICATION_CODE_TIME_OUT, this.VERIFICATION_CODE_TIME_UNIT);
                try {
                    userAccountHelpService.sendVerificationCodeMail(mailInfo);
                } catch (MessagingException | MailException e) {
                    response.setError(ErrorStatus.MAIL_SERVICE_NOT_AVAILABLE);
                    stringCacheService.remove(k);
                }

        }
        UserAccountHelpRequestVO data = new UserAccountHelpRequestVO(vfCode);
        response.setSuccess(data);
        return response;
    }

    private final Object checkLock = new Object();

    @PostMapping("/password_reset")
    @ApiOperation("找回密码-提交重置接口")
    public ApiResult<ApiResult.ApiData> resetPassword(@Validated(value = {UserAccountHelpRequestDTO.ResetPasswordGroup.class})
                                                                    @RequestBody UserAccountHelpRequestDTO request) {
        String k = this.VERIFICATION_CODE_CACHE_PREFIX + request.getUsername();
        ApiResult<ApiResult.ApiData> response = new ApiResult<>();
        try {
            synchronized (checkLock) {
                String target = stringCacheService.get(k);
                boolean match = (!Objects.isNull(target) && target.equals(request.getVerificationCode()));
                if (!match) {
                    throw new VerificationCodeMismatchException("验证码错误!");
                }
                stringCacheService.remove(k);
            }
            userAccountHelpService.resetPassword(request.getUsername(), request.getPassword());
            userAuthorizationService.removeUserTokenByUsername(request.getUsername());
            response.setSuccess(null);
        } catch (VerificationCodeMismatchException e) {
            log.info(e.getMessage());
            response.setError(ErrorStatus.VERIFICATION_CODE_WRONG, e.getMessage());
        } catch (UpdateException e) {
            log.warn(e.getMessage());
            response.setError(ErrorStatus.SERVER_ERROR, e.getMessage());
        }
        return response;
    }


}
